package com.meiqiang.muxinnetty.utils;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * description
 *
 * @author shihuaguo
 * @date 2019/11/28
 **/
@Slf4j
public class FileUtil {

    //随机文件名长度
    private static final int RANDOM_FILE_NAME_LENGTH = 32;

    //随机文件名左填充
    private static final int RANDOM_FILE_LEFT_PADDING = 6;

    private static Random random = new Random();

    @Value("${file.storage.local.dir:/data/radar}")
    protected String fileStorageDir;

    private static String randomStr(int len) {
        char[] chars = new char[len];
        for (int i = 0; i < chars.length; i++) {
            chars[i] = (char) ('A' + random.nextInt(26));
        }
        return new String(chars);
    }

    /**
     * 根据文件名生成随机文件名
     *
     * @param originalFilename original file name
     * @return random file name
     */
    public static String randomFilename(String originalFilename) {
        if (StringUtils.isNotBlank(originalFilename)) {
            int length = Math.min(originalFilename.length(), 16);
            String middleName = originalFilename.substring(0, length);
            int rightPadding = RANDOM_FILE_NAME_LENGTH - RANDOM_FILE_LEFT_PADDING - length;
            return String.format("%s_%s_%s", randomStr(RANDOM_FILE_LEFT_PADDING), middleName, randomStr(rightPadding));

        }
        return originalFilename;
    }

    /**
     * 检查文件夹和文件是否存在,如果不存在则创建
     *
     * @param filePath file path
     * @return if dir and file exists
     * @throws IOException ioexception
     */
    public static boolean checkFile(String filePath) throws IOException {
        boolean flag = true;
        int pos = filePath.lastIndexOf(File.separator);
        if (pos > 0) {
            String dirPath = filePath.substring(0, pos);
            File dir = new File(dirPath);
            if (!dir.exists()) {
                flag = dir.mkdirs();
            }
        }
        if (flag) {
            File file = new File(filePath);
            if (!file.exists()) {
                flag = file.createNewFile();
                log.info("create new file: {}={}", file.getAbsolutePath(), flag);
            }
        }
        return flag;
    }

    public static String getFileName(String filePath) {
        int pos = filePath.lastIndexOf(File.separator);
        if (pos > 0) {
            return filePath.substring(pos + 1);
        }
        return filePath;
    }

    public static String getNameExcludeType(String fileName) {
        if (StringUtils.isNotBlank(fileName)) {
            int pos = fileName.lastIndexOf(".");
            if (pos > 0) {
                return fileName.substring(0, pos);
            }
        }
        return fileName;
    }

    public static String getType(String fileName) {
        if (StringUtils.isNotBlank(fileName)) {
            int pos = fileName.lastIndexOf(".");
            if (pos > 0) {
                return fileName.substring(pos + 1);
            }
        }
        return fileName;
    }

    public static String toUnixPath(String filePath) {
        if (OsUtil.isWindows()) {
            if (filePath.matches("[a-zA-Z]:(?:\\\\.+)*")) {
                String winPath = filePath.replaceFirst("([a-zA-Z]):", "");
                return winPath.replace("\\", "/");
            }
        }
        return filePath;
    }

    public static String readAsString(String filePath) {
        File file = new File(filePath);
        if (file.exists() && file.isFile()) {
            String line;
            StringBuilder sb = new StringBuilder();
            String ls = System.getProperty("line.separator");
            try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                while ((line = br.readLine()) != null) {
                    sb.append(line).append(ls);
                }
                return sb.toString();
            } catch (IOException e) {
                log.error("read from file {} error", filePath, e);
            }
        }
        return "";
    }

    public static List<String> readAsList(String filePath) {
        File file = new File(filePath);
        List<String> list = new ArrayList<>();
        if (file.exists() && file.isFile()) {
            String line;
            try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                while ((line = br.readLine()) != null) {
                    list.add(line);
                }
            } catch (IOException e) {
                log.error("read from file {} error", filePath, e);
            }
        }
        return list;
    }
    
    public static File saveTempFileFromURL(URL url,String prefix,String suffix) {
		try (InputStream is = url.openStream()) {
			File targetFile = File.createTempFile(prefix, suffix);
			OutputStream os = new FileOutputStream(targetFile);
			int bytesRead = 0;
			byte[] buffer = new byte[8192];
			while ((bytesRead = is.read(buffer, 0, 8192)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			return targetFile;
		} catch (IOException e) {
			log.error("文件存储出错,{},{}",e.getMessage(),e.getCause());
			return null;
		}
    }

    /**
     * 上传文件
     *
     * @param file     上传的文件
     * @param filePath 文件保存的文件名
     * @return 成功或失败
     */
    public String uploadFile(@RequestParam("file") MultipartFile file, String filePath) {
        if (StringUtils.isBlank(filePath)) {
            return "上传文件为空";
        }
        try {
            boolean flag = FileUtil.checkFile(filePath);
            if (flag) {
                file.transferTo(new File(filePath));// 文件写入
                String objectName = resolveObjectName(filePath);
                return objectName;
            } else {
                return "文件上传失败";
            }
        } catch (IOException e) {
            log.error("文件上传失败", e);
            return "文件上传失败";
        }
    }

    protected String resolveObjectName(String filePath) {
        String unixPath = FileUtil.toUnixPath(filePath);
        return unixPath.substring(fileStorageDir.length());
    }

    private String getFileSavePath(MultipartFile file) {
        if (file.isEmpty() || StringUtils.isBlank(file.getOriginalFilename())) {
            return null;
        } else {
            String fileName = file.getOriginalFilename();
            // 获取文件的后缀名
            int dotPos = fileName.lastIndexOf(".");
            String prefixName = fileName.substring(0, dotPos);
            String suffixName = fileName.substring(dotPos);
            String randomName = FileUtil.randomFilename(prefixName) + suffixName;
            log.info("上传的文件名为： {}, 随机生成的文件名: {}", fileName, randomName);

            String date = DateUtil.format(new Date(), "yyyy-MM-dd");
            String objectName = "/upload/" + date + "/" + randomName;
            return fileStorageDir + "/" + objectName;
        }
    }

    public String uploadFile(@RequestParam("file") MultipartFile file) {
        String filePath = getFileSavePath(file);
        String resolvedPath = Path.of(filePath).toAbsolutePath().toString();
        return uploadFile(file, resolvedPath);
    }

}
